#include "gui.h"

#include <iostream>
using namespace std;

GUI* GUI::m_instance = NULL;

void 
GUI::glutDisplay(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    glPushMatrix();

    // tramsform camera
    glTranslatef(0, 0, application->m_cameraDistance);
    glRotatef(application->m_cameraAngleX, 0, 1, 0);   // pitch
    glRotatef(application->m_cameraAngleY, 1, 0, 0);   // heading

    // do  a clearscreen
    glClear(GL_COLOR_BUFFER_BIT);

    // Render the correct geometry
    gfx->renderGeometry();

    glPopMatrix();
    glutSwapBuffers();
}

void
GUI::renderGeometry(void)
{
    int solid = application->m_geometryType;

    if (solid)
    {
        switch (application->m_geometry)
        {
            case G_TEAPOT:
                glutSolidTeapot(1.0);
                break;
            case G_TORUS:
                glutSolidTorus(0.25, 0.50, 100, 100);
                break;
            case G_SPHERE:
                glutSolidSphere(0.5, 100, 100);
                break;
            case G_CONE:
                glutSolidCone(0.5, 0.5, 100, 100);
                break;
            case G_CUBE:
                glutSolidCube(0.5);
                break;
            case G_DODECAHEDRON:
                glutSolidDodecahedron();
                break;
            case G_ISOCAHEDRON:
                glutSolidIcosahedron();
                break;
        }
    }
    else
    {
        switch (application->m_geometry)
        {
            case G_TEAPOT:
                glutWireTeapot(0.5);
                break;
            case G_TORUS:
                glutWireTorus(0.25, 0.50, 100, 100);
                break;
            case G_SPHERE:
                glutWireSphere(0.5, 100, 100);
                break;
            case G_CONE:
                glutWireCone(0.5, 0.5, 100, 100);
                break;
            case G_CUBE:
                glutWireCube(0.5);
                break;
            case G_DODECAHEDRON:
                glutWireDodecahedron();
                break;
            case G_ISOCAHEDRON:
                glutWireIcosahedron();
                break;
        }
    }

}

GUI*
GUI::getInstance(void)
{
    if (!m_instance)
    {
        m_instance = new GUI;
    }

    return m_instance;
}

void
GUI::Init(Application *app)
{
    glutInitWindowPosition(50, 50); 
    glutInitWindowSize(300, 300);
    app->m_renderWindow = glutCreateWindow("Render Window");
   
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    // Set the camera
    setCamera(0, 0, 5, 0, 0, 0);
}

void
GUI::setCamera(float posX, float posY, float posZ, 
               float targetX, float targetY, float targetZ)
{
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(posX, posY, posZ, targetX, targetY, targetZ, 0, 1, 0);
}

void
GUI::glutReshape(int width, int height)
{
    // set viewport to be the entire window
    glViewport(0, 0, (GLsizei)width, (GLsizei)height);

    // set perspective viewing frustum
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0f, (float)(width) / height, 1.0f, 1000.0f);

    glMatrixMode(GL_MODELVIEW);
}

void
GUI::drawProgramWindow(Application *app)
{
    int item;

    app->m_programWindow = GLUI_Master.create_glui("Program Window", 0, 360, 360);
    app->m_programWindow->set_main_gfx_window(app->m_renderWindow);

    // Drawing the controls
    // Draw the geometry listbox
    app->c_geometry = app->m_programWindow->add_listbox(app->getString(C_GEOMETRY),
                                                            &app->m_geometry,
                                                            C_GEOMETRY,
                                                            Application::update);
    // Add items to geometry list
    for (item = G_START + 1; item < G_MAX; item++)
    {
        app->c_geometry->add_item(item, app->getString(item));
    }

    // Add the checkbox for solid/wire
    app->c_geometryType = app->m_programWindow->add_checkbox(app->getString(C_GEOMETRYTYPE),
                                                                &app->m_geometryType,
                                                                C_GEOMETRYTYPE,
                                                                Application::update);

    GLUI_EditText* edittext = app->m_programWindow->add_edittext("Vertex",
                                                            GLUI_EDITTEXT_TEXT,
                                                            NULL,
                                                            10,
                                                            Application::update);

}

void
GUI::glutMouseClick(int button, int state, int x, int y)
{
    application->m_mouseX = x;
    application->m_mouseY = y;

    if (button == GLUT_LEFT_BUTTON)
    {
        if (state == GLUT_DOWN)
        {
            application->m_rotateAllowed = true;
        }
        else 
        {
            application->m_rotateAllowed = false;
        }
    }

}


void
GUI::glutMouseMotion(int x, int y)
{
    if (true == application->m_rotateAllowed)
    {
        application->m_cameraAngleX += (x - application->m_mouseX);
        application->m_cameraAngleY -= (y - application->m_mouseY);

        application->m_mouseX = x;
        application->m_mouseY = y;
   
        // Redraw the render window
        glutPostRedisplay();
    }
    
}


